package pl.diagnoser.client;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import pl.diagnoser.client.dto.AttributeDictDTO;
import pl.diagnoser.client.dto.AttributeValuesDictDTO;
import pl.diagnoser.client.dto.DefectDictDTO;
import pl.diagnoser.client.dto.DiagnoserResultDTO;
import pl.diagnoser.client.dto.SymptomDictDTO;
import pl.diagnoser.client.tools.DataGetterService;
import pl.diagnoser.client.tools.DataGetterServiceAsync;
import com.google.gwt.core.client.GWT;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.smartgwt.client.data.RecordList;
import com.smartgwt.client.util.SC;
import com.smartgwt.client.widgets.form.fields.SelectItem;
import com.smartgwt.client.widgets.grid.ListGrid;
import com.smartgwt.client.widgets.grid.ListGridRecord;

public class Dictionary {
	
	private static DataGetterServiceAsync dataGetterAsc = GWT.create(DataGetterService.class);
	private static Dictionary instance;
	
	public static Dictionary getInstance() {
		if(instance == null)
			instance =  new Dictionary();
		return instance;
	}
	
	public void save(ListGridRecord newRecord, final String dictName, final String param, final ListGrid listGrid) {
		if (dataGetterAsc == null) {
			dataGetterAsc = GWT.create(DataGetterService.class);
		}
		
		AsyncCallback<String> callback = new AsyncCallback<String>() {
			public void onFailure(Throwable caught) {
				System.out.println(caught.getMessage());
			}

			public void onSuccess(String result) {
				if(!result.equals("OK"))
					SC.say("Błąd zapisu: " + result);
				else if(dictName == "ATTRIBUTE")
					loadAttributesToGrid(listGrid);
				else if(dictName == "ATTRIBUTE_VALUE")
					loadSelectedAttributeValues(param, listGrid);
				//else if(dictName == "DEFECT")
				//	loadDefectsToGrid(listGrid);
				//else if(dictName == "SYMPTOM")
				//	loadSymptomsToGrid(listGrid);
			}
		};
		
		if(dictName == "ATTRIBUTE") {
			dataGetterAsc.saveAttribute(newRecord.getAttributeAsString("attributeName").replace(" ", "_"), 
					                    (newRecord.getAttributeAsBoolean("isDate") != null && newRecord.getAttributeAsBoolean("isDate") == true ? 1 : 0),
					                    (newRecord.getAttributeAsBoolean("isMultiple") != null && newRecord.getAttributeAsBoolean("isMultiple") == true ? 1 : 0),
					                    (newRecord.getAttributeAsBoolean("isFile") != null && newRecord.getAttributeAsBoolean("isFile") == true ? 1 : 0),
					                    callback);
			DictionaryData.getInstance().getAttributes().clear();
		}
		else if(dictName == "ATTRIBUTE_VALUE") {
			dataGetterAsc.saveAttributeValue(newRecord.getAttributeAsString("name").replace(" ", "_"), param, callback);
			DictionaryData.getInstance().getAttributeValues(param).clear();
		}
		else if(dictName == "DEFECT") {
			dataGetterAsc.saveDefect(newRecord.getAttributeAsString("name"), callback);
		}
		else if(dictName == "SYMPTOM") {
			dataGetterAsc.saveSymptom(newRecord.getAttributeAsString("name"), callback);
		}
	}
	
	public void remove(ListGridRecord[] records, final String dictName, final String param, final ListGrid listGrid) {
		List<ListGridRecord> listGridRecord = Arrays.asList(records);
		ArrayList<String> names = new ArrayList<String>();
		if(dictName == "ATTRIBUTE")
			names.add(records[0].getAttributeAsString("attributeName"));
		else if(dictName == "APP")
			names.add(records[0].getAttributeAsString("appName"));
		else {
			for(ListGridRecord record : listGridRecord)
				names.add(record.getAttributeAsString("name"));
		}
		
		if (dataGetterAsc == null) {
			dataGetterAsc = GWT.create(DataGetterService.class);
		}
		
		AsyncCallback<String> callback = new AsyncCallback<String>() {
			public void onFailure(Throwable caught) {
				System.out.println(caught.getMessage());
			}

			public void onSuccess(String result) {
				if(!result.equals("OK"))
					SC.say("Błąd usuwania: " + result);
				else if(dictName == "ATTRIBUTE")
					loadAttributesToGrid(listGrid);
				else if(dictName == "ATTRIBUTE_VALUE")
					loadSelectedAttributeValues(param, listGrid);
				//else if(dictName == "DEFECT")
				//	loadDefectsToGrid(listGrid);
				//else if(dictName == "SYMPTOM")
				//	loadSymptomsToGrid(listGrid);
			}
		};
		
		if(dictName == "ATTRIBUTE") {
			dataGetterAsc.removeAttribute(names.get(0), callback);
			DictionaryData.getInstance().getAttributes().clear();
		}
		else if(dictName == "ATTRIBUTE_VALUE") {
			dataGetterAsc.removeAttributeValue(names.get(0), param, callback);
			DictionaryData.getInstance().getAttributeValues(param).clear();
		}
		else if(dictName == "DEFECT") {
			dataGetterAsc.removeDefects(names, callback);
		}
		else if(dictName == "SYMPTOM") {
			dataGetterAsc.removeSymptoms(names, callback);
		}
		else if(dictName == "APP") {
			dataGetterAsc.removeApp(names.get(0), callback);
		}
	}
	
	public void loadAttributesToGrid(final ListGrid listGrid) {
		if(DictionaryData.getInstance().isAttributeLoad()) {
			listGrid.setData( DictionaryData.getInstance().getAttributes().toArray(new AttributeRecord[DictionaryData.getInstance().getAttributeRecordsSize()]) );
		} else {
			if (dataGetterAsc == null) {
				dataGetterAsc = GWT.create(DataGetterService.class);
			}
			
			AsyncCallback<List<AttributeDictDTO>> callback = new AsyncCallback<List<AttributeDictDTO>>() {
				public void onFailure(Throwable caught) {
					System.out.println(caught.getMessage());
				}
	
				public void onSuccess(List<AttributeDictDTO> result) {
					listGrid.setData( DictionaryData.getInstance().createAttributeRecords(result).toArray(new AttributeRecord[DictionaryData.getInstance().getAttributeRecordsSize()]) );
				}
			};
			dataGetterAsc.getAttributeList(true, callback);
		}
	}
	
	public void loadSelectedAttributeValues(String attributeName, ListGrid listGrid) {
		if(DictionaryData.getInstance().isAttributeValueLoad(attributeName))
			listGrid.setData(DictionaryData.getInstance().getAttributeValues(attributeName).toArray(new DictionaryRecord[DictionaryData.getInstance().getAttributeValuesRecordsSize(attributeName)]));
		else
			listGrid.setData(new RecordList());
	}
	
	///////////////////////////////////////
	private void loadToCombo(SelectItem combo, ArrayList<DictionaryRecord> records) {
		LinkedHashMap<String, String> retVal = new LinkedHashMap<String, String>();
		int i = 0;
		for(DictionaryRecord record : records) {
			retVal.put("" + i++, record.getName());
		}
		combo.setValueMap(retVal);
	}
	
	public void loadDefectsToCombo(final SelectItem combo) {
		if(DictionaryData.getInstance().isDefectsLoad()) {
			loadToCombo(combo, DictionaryData.getInstance().getDefects());
		} else {
			if (dataGetterAsc == null) {
				dataGetterAsc = GWT.create(DataGetterService.class);
			}
			
			AsyncCallback<List<DefectDictDTO>> callback = new AsyncCallback<List<DefectDictDTO>>() {
				public void onFailure(Throwable caught) {
					System.out.println(caught.getMessage());
				}

				public void onSuccess(List<DefectDictDTO> result) {
					ArrayList<DictionaryRecord> record = DictionaryData.getInstance().createDefectsRecords(result);
					record.add(new DictionaryRecord("brak"));
					loadToCombo(combo, record);
				}
			};
			dataGetterAsc.getDefectsList(callback);
		}
	}
	
	public void loadDefectsToGrid(final ListGrid listGrid) {
        if(DictionaryData.getInstance().isDefectsLoad()) {
                listGrid.setData( DictionaryData.getInstance().getDefects().toArray(new DictionaryRecord[DictionaryData.getInstance().getDefectsRecordsSize()]) );
        } else {
                if (dataGetterAsc == null) {
                        dataGetterAsc = GWT.create(DataGetterService.class);
                }
                
                AsyncCallback<List<DefectDictDTO>> callback = new AsyncCallback<List<DefectDictDTO>>() {
                        public void onFailure(Throwable caught) {
                                System.out.println(caught.getMessage());
                        }

                        public void onSuccess(List<DefectDictDTO> result) {
                                listGrid.setData( DictionaryData.getInstance().createDefectsRecords(result).toArray(new DictionaryRecord[DictionaryData.getInstance().getDefectsRecordsSize()]) );
                        }
                };
                dataGetterAsc.getDefectsList(callback);
        }
	}

	public void loadSymptomsToCombo(final SelectItem combo) {
        if(DictionaryData.getInstance().isSymptomsLoad()) {
                loadToCombo(combo, DictionaryData.getInstance().getSymptoms());
        } else {
                if (dataGetterAsc == null) {
                        dataGetterAsc = GWT.create(DataGetterService.class);
                }
                
                AsyncCallback<List<SymptomDictDTO>> callback = new AsyncCallback<List<SymptomDictDTO>>() {
                        public void onFailure(Throwable caught) {
                                System.out.println(caught.getMessage());
                        }

                        public void onSuccess(List<SymptomDictDTO> result) {
                                ArrayList<DictionaryRecord> record = DictionaryData.getInstance().createSymptomsRecords(result);
                                loadToCombo(combo, record);
                        }
                };
                dataGetterAsc.getSymptomsList(callback);
        }
	}

	public void loadSymptomsToGrid(final ListGrid listGrid) {
        if(DictionaryData.getInstance().isSymptomsLoad()) {
                listGrid.setData( DictionaryData.getInstance().getSymptoms().toArray(new DictionaryRecord[DictionaryData.getInstance().getSymptomsRecordsSize()]) );
        } else {
                if (dataGetterAsc == null) {
                        dataGetterAsc = GWT.create(DataGetterService.class);
                }
                
                AsyncCallback<List<SymptomDictDTO>> callback = new AsyncCallback<List<SymptomDictDTO>>() {
                        public void onFailure(Throwable caught) {
                                System.out.println(caught.getMessage());
                        }

                        public void onSuccess(List<SymptomDictDTO> result) {
                                listGrid.setData( DictionaryData.getInstance().createSymptomsRecords(result).toArray(new DictionaryRecord[DictionaryData.getInstance().getSymptomsRecordsSize()]) );
                        }
                };
                dataGetterAsc.getSymptomsList(callback);
        }
	}

}

class AttributeRecord extends ListGridRecord {
	
	AttributeRecord() {}
	AttributeRecord(String attributeName,int isDate, int isMultiple, int isFile) {
		setAttributeName(attributeName);
		setIsDate(isDate);
		setIsMultiple(isMultiple);
		setIsFile(isFile);
	}
	
	public String getAttributeName() {
		return getAttributeAsString("attributeName");
	}
	public void setAttributeName(String attributeName) {
		setAttribute("attributeName", attributeName);
	}
	
	public int getIsDate() {
		if(getAttributeAsBoolean("isDate"))
			return 1;
		else
			return 0;
	}
	public void setIsDate(int isDate) {
		if(isDate == 1)
			setAttribute("isDate", true);
		else
			setAttribute("isDate", false);
	}
	
	public int getIsMultiple() {
		if(getAttributeAsBoolean("isMultiple"))
			return 1;
		else
			return 0;
	}
	public void setIsMultiple(int isMultiple) {
		if(isMultiple == 1)
			setAttribute("isMultiple", true);
		else
			setAttribute("isMultiple", false);
	}
	
	public int getIsFile() {
		if(getAttributeAsBoolean("isFile"))
			return 1;
		else
			return 0;
	}
	public void setIsFile(int isFile) {
		if(isFile == 1)
			setAttribute("isFile", true);
		else
			setAttribute("isFile", false);
	}
	
	public String getFieldValue(String field) {
		return getAttributeAsString(field);
	}
}

class DictionaryRecord extends ListGridRecord {
	
	DictionaryRecord() {}
	DictionaryRecord(String name) {
		setName(name);
	}
	
	public void setName( String name ) {
		this.setAttribute("name", name);
	}
	
	public String getName() {
		return getAttributeAsString("name");
	}
}

class DictionaryData {
	
	private static DictionaryData instance;
	private ArrayList<DictionaryRecord> defectsRecords = new ArrayList<DictionaryRecord>();
	private ArrayList<DictionaryRecord> symptomsRecords = new ArrayList<DictionaryRecord>();
	
	private ArrayList<AttributeRecord> attributeRecords = new ArrayList<AttributeRecord>();
	private HashMap<String, ArrayList<DictionaryRecord>> attributeToValues = new HashMap<String, ArrayList<DictionaryRecord>>();
	
	public static DictionaryData getInstance() {
		if(instance == null) {
			instance = new DictionaryData();
		}
		return instance;
	}
	
	public ArrayList<DictionaryRecord> createDiagnoserResultRecords(List<DiagnoserResultDTO> defectsDict) {
		for(DiagnoserResultDTO defect : defectsDict) {
			defectsRecords.add(new DictionaryRecord(defect.getDiagnoserResultName()));
		}
		return defectsRecords;
	}
	
	public ArrayList<DictionaryRecord> createDefectsRecords(List<DefectDictDTO> defectsDict) {
        for(DefectDictDTO defect : defectsDict) {
                defectsRecords.add(new DictionaryRecord(defect.getDefectName()));
        }
        return defectsRecords;
	}
	
	public ArrayList<DictionaryRecord> createSymptomsRecords(List<SymptomDictDTO> symptomsDict) {
        for(SymptomDictDTO symptom : symptomsDict) {
                symptomsRecords.add(new DictionaryRecord(symptom.getSymptomName()));
        }
        return symptomsRecords;
	}

	public ArrayList<AttributeRecord> createAttributeRecords(List<AttributeDictDTO> attributeDict) {
		System.out.println("Ładuje:");
		for(AttributeDictDTO attribute : attributeDict) {
			attributeRecords.add(new AttributeRecord(attribute.getAttributeName().replace("_", " "),
					                                 attribute.getIsDate(),
					                                 attribute.getIsMultiple(),
					                                 attribute.getIsFile()));
			ArrayList<DictionaryRecord> tmp = new ArrayList<DictionaryRecord>();
			for(AttributeValuesDictDTO attributeValues : attribute.getAttributeValues()) {
				tmp.add(new DictionaryRecord(attributeValues.getAttributeValue().replace("_", " ")));
			}
			attributeToValues.put(attribute.getAttributeName(), tmp);
		}
		return attributeRecords;
	}
	
	public ArrayList<DictionaryRecord> getDefects() {
		return defectsRecords;
	}
	
	public ArrayList<DictionaryRecord> getSymptoms() {
		return symptomsRecords;
	}
	
	public ArrayList<AttributeRecord> getAttributes() {
		return attributeRecords;
	}
	
	public ArrayList<DictionaryRecord> getAttributeValues(String attribute) {
		return attributeToValues.get((String) attribute);
	}
	
	public Integer getDefectsRecordsSize() {
		return defectsRecords.size();
	}
	
	public Integer getSymptomsRecordsSize() {
		return symptomsRecords.size();
	}
	
	public Integer getAttributeRecordsSize() {
		return attributeRecords.size();
	}
	
	public Integer getAttributeValuesRecordsSize(String attribute) {
		if(attributeToValues.get((String) attribute) == null)
			return 0;
		else
			return attributeToValues.get((String) attribute).size();
	}
	
	public boolean isDefectsLoad() {
		if(defectsRecords.isEmpty())
			return false;
		return true;
	}
	
	public boolean isSymptomsLoad() {
		if(symptomsRecords.isEmpty())
			return false;
		return true;
	}
	
	public boolean isAttributeLoad() {
		if(attributeRecords.isEmpty())
			return false;
		return true;
	}
	
	public boolean isAttributeValueLoad(String attribute) {
		if(attributeToValues.get(attribute) == null)
			return false;
		return true;
	}
}
